package com.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.common.DataQualityCheckException;
import com.constant.CommonConstants;
import com.entity.dto.MySQLExportDto;
import com.entity.param.MySQLSchemaParam;
import com.entity.vo.ColumnVo;
import com.entity.vo.MySqlTablesVo;
import com.mapper.MySqlSchemaMapper;
import com.service.MySqlSchemaService;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author xiaoshu
 * @description
 * @date 2024年03月12日 23:43
 */
@Service
public class MySqlSchemaServiceImpl implements MySqlSchemaService {
    @Resource
    private JdbcTemplate jdbcTemplate;

    @Resource
    private MySqlSchemaMapper mySqlSchemaMapper;

    @Override
    public Boolean exportDataToFile(MySQLExportDto mySQLExportDto) {
        String sql="";
        if (StringUtils.hasLength(mySQLExportDto.getDateColumn())){
            sql="SELECT * INTO OUTFILE '%s' FIELDS TERMINATED BY ',' LINES TERMINATED BY '\\n' FROM `%s`.`%s` where %s <= '%s' ";
        }else {
            sql="SELECT * INTO OUTFILE '%s' FIELDS TERMINATED BY ',' LINES TERMINATED BY '\\n' FROM `%s`.`%s`";
        }
        String executeSql = String.format(sql, mySQLExportDto.getExportFilePath(),
                mySQLExportDto.getDataBaseName(),
                mySQLExportDto.getTableName(),
                mySQLExportDto.getDateColumn(),
                mySQLExportDto.getDate());
        jdbcTemplate.execute(executeSql);
        return Boolean.TRUE;
    }

    @Override
    public List<MySqlTablesVo> schemaTables(String databaseName) {
        List<MySqlTablesVo> tables = mySqlSchemaMapper.schemaTables(databaseName);
        if (CollectionUtil.isNotEmpty(tables)){
            tables.forEach(e->{
                if (e.getDataLength()!=null){
                    e.setShowDataLength(showSize(e.getDataLength()));
                }
                if (e.getIndexLength()!=null){
                    e.setShowIndexLength(showSize(e.getIndexLength()));
                }
            });
        }
        return tables;
    }

    @Override
    public List<Map<String, Object>> queryList(MySQLSchemaParam param) {
        if (!StringUtils.hasLength(param.getOrderByValue())){
            param.setOrderByValue("asc");
        }
        List<ColumnVo> columnVos = queryColumn(param);
        String orderByColumn = param.getOrderByColumn();
        String sqlColumn = getSQLColumn(columnVos);
        if (StringUtils.hasLength(orderByColumn)){
            for (String s : orderByColumn.split(",")) {
                if (!sqlColumn.contains(s)){
                    throw new DataQualityCheckException("排序字段不存在");
                }
            }
        }
        param.setColumns(sqlColumn);
        String priKeys = getPriKey(columnVos);
        if (StringUtils.hasLength(priKeys) && !StringUtils.hasLength(param.getOrderByColumn())){
            param.setOrderByColumn(priKeys);
            param.setOrderByValue("asc");
        }
        return mySqlSchemaMapper.queryList(param);
    }

    @Override
    public List<ColumnVo> queryColumn(MySQLSchemaParam param) {
        List<ColumnVo> columnVos = new LinkedList<>();
        List<Map<String, String>> column = mySqlSchemaMapper.queryColumn(param);
        column.forEach(e->{
            ColumnVo vo = new ColumnVo();
            vo.setColName(e.getOrDefault("Field",""));
            vo.setDataType(e.getOrDefault("Type",""));
            vo.setComment(e.getOrDefault("Comment",""));
            vo.setKey(e.getOrDefault("Key",""));
            columnVos.add(vo);
        });
        return columnVos;
    }

    @Override
    public Map<String, String> columnCommentMap(MySQLSchemaParam param) {
        List<ColumnVo> columnVos = queryColumn(param);
        return columnVos.stream().collect(Collectors.toMap(ColumnVo::getColName, ColumnVo::getComment));
    }

    @Override
    public String getSQLColumn(List<ColumnVo> columns) {
        List<String> columnStrs = columns.stream().map(ColumnVo::getColName).collect(Collectors.toList());
        Collections.sort(columnStrs);
        return String.join(",", columnStrs);
    }

    @Override
    public String getPriKey(List<ColumnVo> columns) {
        List<String> columnStrs = columns.stream()
                .filter(e->e.getKey().equals(CommonConstants.PRI_KEY))
                .map(ColumnVo::getColName).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(columnStrs)){
            return "";
        }
        return String.join(",", columnStrs);
    }

    @Override
    public Long queryCount(MySQLSchemaParam param) {
        return mySqlSchemaMapper.queryCount(param);
    }

    public static String showSize(long bytes) {
        if (bytes < 1024) {
            return bytes + " B";
        } else if (bytes < 1024 * 1024) {
            double kb = (double) bytes / 1024;
            return String.format("%.2f KB", kb);
        } else if (bytes < 1024 * 1024 * 1024) {
            double mb = (double) bytes / (1024 * 1024);
            return String.format("%.2f MB", mb);
        } else {
            double gb = (double) bytes / (1024 * 1024 * 1024);
            return String.format("%.2f GB", gb);
        }
    }
}
